/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.dotexe.webframework.core.datasources;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.dotexe.webframework.core.bindings.BindingObjectSource;
import com.dotexe.webframework.core.eventargs.DataUpdate;
import com.dotexe.webframework.core.eventargs.RefreshStateArgs;

/**
 *
 * @author jovan.tomasevic
 */
public class ObjectDataSource extends DataSource {

    public ObjectDataSource() {
        super();
    }

    public ObjectDataSource(String name) {
        super(name);
    }

    @Override
    public void setSource(Object source) {
        this.Source = source;
    }

    public void bind(ArrayList<String> propertiesTiBind)
            throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, JSONException, NoSuchMethodException, InvocationTargetException {
        BindingObjectSource binding = new BindingObjectSource();
        binding.setName(this.getName());
        JSONObject json = null;
        JSONArray jsonPropertiesToBind = new JSONArray();
        if (this.getSource() != null) {
            Class cls = this.getSource().getClass();
            json = new JSONObject();
            for (int i = 0; i < propertiesTiBind.size(); i++) {
                String methodName = this.createGetMethodName(propertiesTiBind.get(i));
                Method m = cls.getMethod(methodName);
                Object fValue = m.invoke(this.Source);
                if (fValue == null) {
                    fValue = JSONObject.NULL;
                }
                json.put(propertiesTiBind.get(i), fValue);
                jsonPropertiesToBind.put(propertiesTiBind.get(i));
            }
        }
        binding.setSource(json);
        binding.setPropertiesToBind(jsonPropertiesToBind);
        this.BindingSource = binding;
    }

    public void bind()
            throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, JSONException, NoSuchMethodException, InvocationTargetException {
        ArrayList<String> properties = new ArrayList<String>();
        if (this.getSource() != null) {
            Field[] fields = this.getSource().getClass().getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                Field f = fields[i];
                properties.add(f.getName());
            }
        }
        this.bind(properties);
    }

    public void update(RefreshStateArgs args, DataUpdate update) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, JSONException, ParseException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
        if (update == null) {
            return;
        }
        Class sourceType = this.Source.getClass();
        Method getMethod = sourceType.getMethod(this.createGetMethodName(update.dataMemberName));
        Class propertyType = getMethod.getReturnType();
        Object value = null;
        Method setMethod = null;
        if (propertyType.getName().equals(Integer.class.getName()) || propertyType.getName().equals(int.class.getName())) {
            value = Integer.parseInt(update.value.toString());
            String setMethodName = this.createSetMethodName(update.dataMemberName);
            setMethod = sourceType.getMethod(setMethodName, int.class);
        } else if (propertyType.getName().equals(Boolean.class.getName()) || propertyType.getName().equals(boolean.class.getName())) {
            value = Boolean.parseBoolean(update.value.toString());
            String setMethodName = this.createSetMethodName(update.dataMemberName);
            setMethod = sourceType.getMethod(setMethodName, Boolean.class);
        } else if (propertyType.getName().equals(Float.class.getName()) || propertyType.getName().equals(float.class.getName())) {
            value = Float.parseFloat(update.value.toString());
            String setMethodName = this.createSetMethodName(update.dataMemberName);
            setMethod = sourceType.getMethod(setMethodName, Float.class);
        } else if (propertyType.getName().equals(Date.class.getName())) {
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            String dateString = update.value.toString().replace('T', ' ');
            value = dateFormat.parse(dateString);
            String setMethodName = this.createSetMethodName(update.dataMemberName);
            setMethod = sourceType.getMethod(setMethodName, Date.class);
        } else if (propertyType.getName().equals(Double.class.getName()) || propertyType.getName().equals(double.class.getName())) {
            value = Double.parseDouble(update.value.toString());
            String setMethodName = this.createSetMethodName(update.dataMemberName);
            setMethod = sourceType.getMethod(setMethodName, Double.class);
        } else {
            value = update.value.toString();
            String setMethodName = this.createSetMethodName(update.dataMemberName);
            setMethod = sourceType.getMethod(setMethodName, String.class);
        }

        setMethod.invoke(this.Source, value);
    }
}
